package com.fast.alden.admin.service.impl;

import com.fast.alden.admin.service.SysOnlineUserService;
import com.fast.alden.admin.service.SysUserService;
import com.fast.alden.admin.util.Constants;
import com.fast.alden.common.entity.vo.SysOnlineUser;
import com.fast.alden.common.exception.BizException;
import com.fast.alden.common.exception.BizExceptionEnum;
import com.fast.alden.common.service.RedisService;
import com.fast.alden.common.service.TokenService;
import com.fast.alden.common.util.ServletUtils;
import com.fast.alden.data.model.BaseEntity;
import com.fast.alden.data.model.SysUser;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SysOnlineUserServiceImpl implements SysOnlineUserService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RedisService redisService;
    @Resource
    private SysUserService userService;
    @Resource
    private TokenService tokenService;
    @Value("${fast-alden.secure.jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${fast-alden.secure.jwt.tokenHead}")
    private String tokenHead;

    @Override
    public List<SysOnlineUser> search(SysOnlineUser searchVo) {
        Set<String> keys = redisTemplate.keys(Constants.CACHE_KEY_PREFIX_SYS_USER_ONLINE + "*");

        List<SysOnlineUser> onlineUsers = new ArrayList<>();
        if (keys != null) {
            List<Long> userIds = keys.stream()
                    .map((key) -> (SysOnlineUser) redisService.get(key))
                    .map(SysOnlineUser::getUserId)
                    .toList();
            Map<Long, SysUser> userMap = userService.list(userIds).stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

            onlineUsers = keys.stream()
                    .map((key) -> {
                        SysOnlineUser cache = (SysOnlineUser) redisService.get(key);
                        SysUser user = userMap.get(cache.getUserId());
                        SysOnlineUser onlineUser = SysOnlineUser.load(user);
                        onlineUser.setIp(cache.getIp());
                        onlineUser.setUserId(cache.getUserId());
                        onlineUser.setLoginTime(cache.getLoginTime());
                        onlineUser.setToken(cache.getToken());
                        return onlineUser;
                    })
                    .sorted(Comparator.comparing(SysOnlineUser::getLoginTime).reversed())
                    .toList();
        }
        return onlineUsers;
    }

    @Override
    public void forceLogout(String token) {
        // 当前请求携带的token
        String authHeader = ServletUtils.getRequest().getHeader(this.tokenHeader);
        // "Bearer "后的部分
        String authToken = authHeader.substring(this.tokenHead.length());
        // 如果要操作的token和当前请求token相同
        if (authToken.equals(token)) {
            throw new BizException(BizExceptionEnum.USER_CANT_FORCE_LOGOUT_HIMSELF);
        }

        String username = tokenService.getUserNameFromToken(token);

        // 从redis中删除token
        String key = Constants.CACHE_KEY_PREFIX_SYS_USER_ONLINE + username + ":" + token;
        redisService.del(key);
    }
}
